<template>
    <div v-loading="loading" class="console-page">
        <el-form inline :model="searchForm" class="e-page form-item" spellcheck="false" @submit.native.prevent>
            <el-row class="search toolbar">
                <el-col :span="4" style="padding-right: 5px" v-if="!fromJob">
                    <el-input class="input-auto-resize" v-model="searchForm.jobName" placeholder="任务名称" clearable />
                </el-col>
                <el-col :span="4" style="padding-right: 5px">
                    <el-select v-model="searchForm.logStatus" placeholder="任务状态" collapse-tags class="input-auto-resize"
                        clearable>
                        <el-option v-for="item in statusSelect" :key="item.value" :label="item.label"
                            :value="item.value" />
                    </el-select>
                </el-col>
                <el-col :span="4" style="padding-right: 5px">
                    <el-date-picker v-model="searchForm.filterTime" type="daterange" unlink-panels range-separator="~"
                        start-placeholder="开始时间" end-placeholder="结束时间" :shortcuts="shortcuts" class="input-auto-resize"
                        format="YYYY/MM/DD" value-format="YYYY-MM-DD" popper-class="poper-auto-reisze"
                        :disabled-date="disabledDate" />
                </el-col>
                <el-col :span="4" style="padding-right: 5px">
                    <el-button type="primary" @click="searchTable" circle :icon="getIcon('search')"
                        :loading="bt_loading" class="button-auto-resize" native-type="submit" />
                </el-col>
            </el-row>
        </el-form>
        <el-table :data="tableData" border header-cell-class-name="el-table-header-cell" cell-class-name="el-table-cell"
            class="e-page table-with-pagination" ref="tableRef" highlight-current-row>
            <el-table-column prop="id" label="日志ID" :min-width="fontAutoResize.size_7.value" />
            <el-table-column prop="jobName" label="任务名称" min-width="250" v-if="!fromJob">
                <template #default="scope">
                    <span @click="go(scope.row)" :class="setClass(scope.row)">{{ scope.row.jobName }}</span>
                </template>
            </el-table-column>
            <el-table-column prop="jobType" label="任务类型" :width="fontAutoResize.size_8.value">
                <template #default="scope">
                    <el-tag type="primary" class="forbid-select input-auto-resize" effect="plain" disable-transitions>
                        {{ getGlueType(scope.row.jobType).toUpperCase() }}
                    </el-tag>
                </template>
            </el-table-column>
            <el-table-column prop="triggerCode" label="调度类型" :width="fontAutoResize.size_8.value">
                <template #default="scope">
                    <el-tag :type="scope.row.triggerMsg && scope.row.runType === '手动执行' ? 'info' : 'success'"
                        class="forbid-select input-auto-resize" effect="plain" disable-transitions>
                        {{ scope.row.runType }}
                    </el-tag>
                </template>
            </el-table-column>
            <el-table-column prop="triggerTime" label="日志记录时间" :width="fontAutoResize.size_12.value">
                <template #default="scope">
                    <span>{{ scope.row.createTime }}</span>
                </template>
            </el-table-column>
            <el-table-column prop="triggerTime" label="调度时间" :width="fontAutoResize.size_12.value">
                <template #default="scope">
                    <span>{{ timeFormatSeconds(scope.row.triggerTime) }}</span>
                </template>
            </el-table-column>
            <el-table-column prop="triggerCode" label="调度状态" :width="fontAutoResize.size_8.value">
                <template #default="scope">
                    <el-tag :type="getTagType(scope.row.triggerCode)" class="forbid-select input-auto-resize"
                        effect="plain" disable-transitions>
                        {{ transferTriggerCode(scope.row.triggerCode) }}
                    </el-tag>
                </template>
            </el-table-column>
            <el-table-column prop="triggerMsg" label="调度信息" :min-width="fontAutoResize.size_6.value">
                <template #default="scope">
                    <span style="cursor: pointer;color: #409EFF" @click="showMsg(scope.row, 1)"
                        v-if="scope.row.triggerMsg" class="cursor-pointer">查看</span>
                    <span v-else>无</span>
                </template>
            </el-table-column>
            <el-table-column prop="handleTime" label="完成时间" :width="fontAutoResize.size_12.value">
                <template #default="scope">
                    <span>{{ timeFormatSeconds(scope.row.handleTime) }}</span>
                </template>
            </el-table-column>
            <el-table-column prop="handleCode" label="执行状态" width="150">
                <template #default="scope">
                    <el-tag :type="scope.row.handleCode === 200 ? 'success' : 'info'"
                        class="forbid-select input-auto-resize" effect="plain" v-if="scope.row.triggerCode === 200"
                        disable-transitions>
                        {{ execStatus(scope.row).status }}
                    </el-tag>
                    <span v-else />
                </template>
            </el-table-column>
            <el-table-column prop="handleMsg" label="执行信息" width="150">
                <template #default="scope">
                    <span style="cursor: pointer;color: #409EFF" @click="showMsg(scope.row, 2)"
                        v-if="scope.row.handleMsg" class="cursor-pointer">查看</span>
                    <el-tag :type="scope.row.handleCode === 200 ? 'success' : 'info'"
                        class="forbid-select input-auto-resize" effect="plain"
                        v-if="scope.row.triggerCode === 200 && !scope.row.handleMsg" disable-transitions>
                        {{ execStatus(scope.row).status }}
                    </el-tag>
                </template>
            </el-table-column>
            <el-table-column fixed="right" label="操作" :width="operationWidth" className="operation-column">
                <template #default="scope">
                    <el-button type="danger" :icon="getIcon('close')" circle class="button-auto-resize"
                        v-if="scope.row.triggerCode === 200 && scope.row.handleCode === 0" @click="stop(scope.row.id)"
                        confirm-title="确定结束该任务?" :loading="stopLoading" v-permission="$permission.Update" />
                    <el-button type="danger" :icon="getIcon('close')" circle class="button-auto-resize"
                        v-if="scope.row.triggerCode === 100 && scope.row.runType === '预约执行'" :loading="stopLoading"
                        @click="cancel(scope.row.id)" confirm-title="确定取消预约执行计划?" v-permission="$permission.Update" />
                    <el-button type="primary" :icon="getIcon('document')" circle class="button-auto-resize"
                        @click="scope.row.triggerCode === 200 ? showLogDetail(scope.row) : showMsg(scope.row, 1)" />
                    <el-button type="danger" :icon="getIcon('delete')" circle class="button-auto-resize"
                        v-if="scope.row.handleCode >= 200 || scope.row.triggerCode >= 200"
                        @click="deleteLog(scope.row.id)" :confirm-title="`确定删除编号${scope.row.id}的日志记录?`" />
                </template>
            </el-table-column>
        </el-table>
        <div style="height: 50px;">
            <el-pagination background @size-change="SizeChange" @current-change="CurrentChange"
                :current-page="currentPage" :page-sizes="page_sizes" :page-size="page_size"
                layout="total, sizes, prev, pager, next, jumper" prev-text="<上一页" next-text="下一页>" :total="total"
                class="e-page">
            </el-pagination>
        </div>

        <el-dialog :title="dialogInfo.title" v-model="showDialog" width="80%" :show-close="false" @closed="close"
            @open="open" append-to-body class="tasklog">
            <p v-html="dialogInfo.msg" class="logMsg" v-if="dialogInfo.type === 1" ref="logMsg" />
            <highlight :code="dialogInfo.msg" style="height: 55vh" v-else />
        </el-dialog>
    </div>
</template>

<script setup>
import { timeFormatSeconds, encrypt, getRandomKey, deepCopy, getIcon } from '@/utils/tools'
import { useElMessage, useSetTableOperationWidth, useModalSize, useRequest, useTableData } from "@usehook"
import router from "@/router"
import { isArray } from "@vue/shared"
import { fontAutoResize } from "@/utils/setting"
import storeInstance from "@/pinia"

const operationWidth = useSetTableOperationWidth(3)

const props = defineProps({
    fromJob: {
        type: Boolean,
        default: () => {
            return false
        }
    }
})

let tableData = ref([])
let currentPage = $ref(1)
let page_size = $ref(0)
let total = $ref(0)
let showDialog = $ref(false)
let dialogInfo = $ref({ msg: "", title: "", type: "" })
let statusSelect = [
    { label: "成功", value: 1 },
    { label: "失败", value: 2 },
    { label: "正在执行", value: 3 },
    { label: "等待开始", value: 4 },
    { label: "任务终止", value: 5 }]
let searchForm = $ref({
    logStatus: null,
    jobName: null,
    filterTime: null
})

const transferTriggerCode = (triggerCode) => {
    switch (triggerCode) {
        case 200:
            return "成功"
        case 0:
            return "分配执行器"
        case 100:
            return "等待开始"
        case 400:
            return "错过调度"
        case 500:
            return "失败"
        case 503:
            return "任务终止"
        default:
            return "失败"
    }
}

const getTagType = (triggerCode) => {
    switch (triggerCode) {
        case 200:
            return "success"
        case 500:
            return "danger"
        default:
            return "info"
    }
}

const searchValue = $computed(() => {
    const { filterTime, ...packageParams } = searchForm
    return { ...packageParams, filterTime: isArray(filterTime) ? filterTime.join(",") : filterTime }
})

let loading = $ref(false)
let bt_loading = $ref(false)
let stopLoading = $ref(false)
let page_sizes = [10, 30, 50, 100, 200]
let shortcuts = [{
    text: '最近一周',
    value() {
        const end = new Date();
        const start = new Date();
        start.setDate(start.getDate() - 7);
        start.setDate(start.getDate() + 1);
        return [start, end];
    }
}, {
    text: '最近一个月',
    value() {
        const end = new Date();
        const start = new Date();
        start.setMonth(start.getMonth() - 1);
        start.setDate(start.getDate() + 1);
        return [start, end];
    }
}, {
    text: '最近三个月',
    value() {
        const end = new Date();
        const start = new Date();
        start.setMonth(start.getMonth() - 3);
        start.setDate(start.getDate() + 1);
        return [start, end];
    }
}]

const open = () => {
    useModalSize()
}
const close = () => {
    useModalSize(false)
}
const execStatus = (row) => {
    if (row.triggerCode !== 200) {
        return { status: "" }
    } else if (row.handleCode === 503) {
        return { status: '任务终止' }
    } else if (row.handleCode === 200) {
        return { status: '成功' }
    } else if (row.triggerCode === 200 && row.handleCode === 0) {
        return { status: '执行中' }
    } else if ((row.triggerCode !== 200 && row.triggerCode !== 0) || (row.handleCode !== 200 && row.handleCode !== 0)) {
        return { status: '失败' }
    } else {
        return { status: "" }
    }
}

const logMsg = $ref(null)

const showMsg = (row, type) => {
    if (type === 1) {
        dialogInfo.title = '调度信息'
        dialogInfo.msg = row.triggerMsg
    } else {
        dialogInfo.title = '执行信息'
        dialogInfo.msg = row.handleMsg
    }
    dialogInfo.type = type
    showDialog = true
    nextTick(() => {
        if (logMsg) logMsg.scrollTop = 0
    })
}

const showLogDetail = (row) => {
    let key = {
        executorAddress: row.executorAddress,
        triggerTime: new Date(row.triggerTime).getTime(),
        logId: row.id,
        fromLineNum: 1
    }
    let encKey = encrypt(JSON.stringify(key), getRandomKey())
    storeInstance.tagMenuStore.setTitle(row.jobName)
    const query = { key: encodeURIComponent(encKey), title: row.jobName }
    router.push({ path: "/task/log", query })
}

const deleteLog = (id) => {
    useRequest.post("/joblog/logRemove", { id }).then((resp) => {
        if (resp && resp.status) {
            useElMessage("日志删除成功")
            refreshTable()
        } else {
            if (resp.message) useElMessage.error(resp.message)
        }
    })
}

const go = (row) => {
    const jobId = row.jobId;
    let taskType = getGlueType(row.jobType);
    const jobName = row.jobName;

    if (jobId) {
        const path = '/task/' + taskType + '?id=' + jobId
        storeInstance.tagMenuStore.setTitle(jobName)
        router.push(path)
    }
}

const getGlueType = (jobType) => {
    jobType = jobType && jobType.startsWith("GLUE") ? jobType.split("_")[1].toLowerCase() : ""
    return jobType === "groovy" ? "java" : jobType;
}
const setClass = (row) => {
    const jobId = row.jobId
    let jobType = row.jobType && row.jobType.startsWith("GLUE") ? row.jobType.split("_")[1] : ""
    const jobName = row.jobName
    return jobId && jobType && jobName ? "underline-left cursor-pointer" : ""
}

const stop = (id) => {
    stopLoading = true
    useRequest({
        url: '/joblog/logKill', method: "post", id: id
    }).then((resData) => {
        if (resData) {
            if (resData.message) useElMessage.error(resData.message)
        }
    }).finally(() => {
        stopLoading = false
        refreshTable()
    })
}

const cancel = (id) => {
    stopLoading = true
    useRequest({
        url: '/joblog/logCancel', method: "post", id: id
    }).then((resData) => {
        if (resData) {
            if (resData.message) useElMessage.error(resData.message)
        }
    }).finally(() => {
        stopLoading = false
        refreshTable()
    })
}

const disabledDate = (date) => {
    return date.getTime() > Date.now()
}

const setData = useTableData("tableRef", tableData)
const getServiceLog = (params) => {
    loading = true;
    bt_loading = true;
    let copyParams = deepCopy(params);

    copyParams['jobId'] = props.fromJob ? router.currentRoute.value.query.id : copyParams.jobId ? copyParams.jobId : 0

    if (copyParams.filterTime) {
        let splitTime = copyParams.filterTime.split(",");
        copyParams['filterTime'] = splitTime[0] + " 00:00:00 - " + splitTime[1] + " 23:59:59"
    }

    useRequest('/joblog/getPageData', copyParams).then(resp => {
        setData(resp.data)
        total = resp.totalRecord
    }).finally(_ => {
        loading = false
        bt_loading = false
    })
}

const searchTable = () => {
    getServiceLog({
        ...searchValue, limit: page_size, page: 1
    });
    currentPage = 1;
}
const refreshTable = () => {
    setTimeout(() => {
        getServiceLog({
            ...searchValue, limit: page_size, page: currentPage
        })
    }, 10);
}
const SizeChange = (val) => {
    getServiceLog({
        ...searchValue, limit: val, page: currentPage
    })
    page_size = val;
}
const CurrentChange = (val) => {
    getServiceLog({
        ...searchValue, limit: page_size, page: val
    })
    currentPage = val;
}

onMounted(() => {
    page_size = page_sizes[1];

    if (!props.fromJob) {
        searchTable()
    }
})
</script>

<style>
.tasklog .logMsg {
    margin: 10px;
    line-height: calc(var(--font-size) * 1.8);
    font-size: var(--font-size);
    max-height: 50vh;
    overflow-y: auto;
}

.tasklog.el-dialog .el-dialog__body {
    padding: 5px !important;
}

.tasklog.el-dialog .el-dialog__header {
    border-bottom: 1px solid #e4e7ec;
}

.tasklog.el-dialog .el-dialog__footer {
    padding: 5px 20px 5px;
    border-top: 1px solid #e4e7ec;
}
</style>

<style scoped>
:deep(.el-form-item) {
    margin-bottom: 0
}

:deep(.el-form-item__content) {
    line-height: 25px;
}

:deep(.el-form-item__label) {
    line-height: 24px;
}

:deep(.el-button+.el-button) {
    margin-left: 2px;
}
</style>